package com.smedi.ismedi.authoritymanagement.core.application.query.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.smedi.ismedi.authority.starter.util.AuthorityUtil;
import com.smedi.ismedi.authoritymanagement.core.application.command.RoleAssignmentListQueryCommand;
import com.smedi.ismedi.authoritymanagement.core.application.command.RoleListQueryCommand;
import com.smedi.ismedi.authoritymanagement.core.application.convert.AppConverter;
import com.smedi.ismedi.authoritymanagement.core.application.query.RoleBasicQueryService;
import com.smedi.ismedi.authoritymanagement.core.application.query.vo.RoleBasicVo;
import com.smedi.ismedi.authoritymanagement.core.application.query.vo.RoleMemberVo;
import com.smedi.ismedi.authoritymanagement.core.domain.aggregatemodel.Role;
import com.smedi.ismedi.authoritymanagement.core.domain.aggregatemodel.RoleAssignment;
import com.smedi.ismedi.authoritymanagement.core.domain.aggregatemodel.RoleBasic;
import com.smedi.ismedi.authoritymanagement.core.domain.aggregatemodel.RoleMember;
import com.smedi.ismedi.authoritymanagement.core.domain.dto.RoleAssignmentQuery;
import com.smedi.ismedi.authoritymanagement.core.domain.dto.RoleQuery;
import com.smedi.ismedi.authoritymanagement.core.domain.repository.RoleBasicRepository;
import com.smedi.ismedi.authoritymanagement.core.domain.repository.RoleMemberRepository;
import com.smedi.ismedi.authoritymanagement.core.port.adapter.persistence.mybatis.mapper.RoleBasicMapper;
import com.smedi.ismedi.authoritymanagement.core.port.adapter.persistence.mybatis.mapper.RoleMemberMapper;
import com.smedi.ismedi.authoritymanagement.core.port.adapter.service.PersonnelRemoteApiService;
import com.smedi.ismedi.personnel.api.dto.response.PersonSimpleResponse;
import com.smedi.ismedi.web.starter.util.DozerUtil;
import com.smedi.ismedi.web.starter.util.SegmentateUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.smedi.ismedi.authoritymanagement.core.infrastructure.constant.ConstantField.PersonLevelEnum.INSTITUTION;
import static com.smedi.ismedi.authoritymanagement.core.infrastructure.constant.ConstantField.RoleTypeEnum.PROJECT_ROLE;

/**
 * @Author: xulinjun
 * @Date: 2021-8-10 16:46
 */
@Slf4j
@Service
@AllArgsConstructor
public class RoleBasicQueryServiceImpl implements RoleBasicQueryService {
    private final DozerUtil dozerUtil;
    private final SegmentateUtil segmentateUtil;
    private final AppConverter appConverter;
    private final RoleBasicMapper roleBasicMapper;
    private final RoleMemberMapper roleMemberMapper;
    private final RoleMemberRepository roleMemberRepository;
    private final RoleBasicRepository roleBasicRepository;
    private final PersonnelRemoteApiService personnelRemoteApiService;
    private final AuthorityUtil authorityUtil;

    @Override
    public IPage getRoleBasicPaginationByRoleName(Long offset, Long pageSize, String roleName, String roleType) {
        Page<RoleBasicVo> page = new Page<>(offset, pageSize);
        page.addOrder(new OrderItem().desc("latest_updated_date"));

        List<String> roleTypes = new ArrayList<>();
        String personLevel = authorityUtil.getLoginAccess().getPersonLevel();
        if (!personLevel.equals(INSTITUTION.name())) {
            roleTypes.add(PROJECT_ROLE.name());
        }

        IPage<RoleBasicVo> pagination = roleBasicMapper.selectRoleBasicPagination(page, roleName, roleType, roleTypes);
        return pagination;
    }

    @Override
    public IPage getRoleMemberPaginationByLastNameAndUserNameAndMobile(Long offset, Long pageSize, Long roleId, String lastName, String userName, String mobile) {
        Page<RoleMemberVo> page = new Page<>(offset, pageSize);
        page.addOrder(new OrderItem().desc("id"));
        List<List<Long>> seg = segmentateUtil.doCut(personnelRemoteApiService.getPersonIdsByLastNameAndUserNameAndMobile(lastName, userName, mobile), 999);

        IPage<RoleMemberVo> pagination = roleMemberMapper.selectRoleMemberVoPaginationByPersonIds(page, roleId, seg);
        List<Long> personIds = pagination.getRecords().stream().map(RoleMemberVo::getPersonId).collect(Collectors.toList());
        List<PersonSimpleResponse> personSimpleList = personnelRemoteApiService.getPersonSimpleByPersonIds(personIds);

        pagination.getRecords().stream().forEach(roleMemberVo -> {
            Optional<PersonSimpleResponse> optional = personSimpleList.stream().filter(person -> person.getPersonId().equals(roleMemberVo.getPersonId())).findFirst();
            if (optional.isPresent()) {
                PersonSimpleResponse data = optional.get();
                roleMemberVo.setLastName(data.getLastName())
                        .setMobile(data.getMobile())
                        .setUserName(data.getUserName())
                        .setInternal(data.isInternal())
                        .setPersonTypeMeaning(data.isInternal() ? "企业" : "项目");
            }
        });

        return pagination;
    }

    @Override
    public List<RoleBasicVo> getRolesByPersonId(Long personId) {
        List<RoleBasicVo> list = new ArrayList<>();
        List<RoleMember> roleMembers = roleMemberRepository.selectRoleMemberByPersonId(personId);

        roleMembers.stream().forEach(roleMember -> {
            RoleBasic roleBasic = roleBasicRepository.selectByRoleId(roleMember.getRoleId());
            if (roleBasic != null) {
                RoleBasicVo vo = dozerUtil.convertor(roleBasic, RoleBasicVo.class);
                vo.setRoleMemberId(roleMember.getRoleMemberId());

                list.add(vo);
            }
        });

        return list;
    }

    @Override
    public List<Long> getPersonIdsByRoleId(Long roleId) {
        return roleMemberRepository.selectRoleMemberByRoleId(roleId).stream().map(RoleMember::getPersonId).collect(Collectors.toList());
    }

    @Override
    public List<Long> getPersonIdsByRoleId(List<Long> roleIds) {
        return roleMemberRepository.selectRoleMemberByRoleId(roleIds).stream().map(RoleMember::getPersonId).collect(Collectors.toList());
    }

    @Override
    public List<RoleBasicVo> getRolesByRoleName(String roleName, boolean fuzzy, boolean showPersonId) {
        List<RoleBasicVo> roleBasicVos = dozerUtil.convertor(roleBasicRepository.selectByRoleName(roleName, fuzzy), RoleBasicVo.class);

        if (showPersonId) {
            roleBasicVos.stream().forEach(roleBasicVo -> {
                roleBasicVo.setRoleOwnerPersonIds(getPersonIdsByRoleId(roleBasicVo.getRoleId()));
            });
        }

        return roleBasicVos;
    }

    @Override
    public List<Role> getRoleList(RoleListQueryCommand roleListQueryCommand) {
        RoleQuery roleQuery = appConverter.roleListQueryCommandToRoleQuery(roleListQueryCommand);
        return roleBasicRepository.getRoleList(roleQuery);
    }

    @Override
    public List<Role> getRoleListWithoutToken(RoleListQueryCommand roleListQueryCommand) {
        RoleQuery roleQuery = appConverter.roleListQueryCommandToRoleQuery(roleListQueryCommand);
        return roleBasicRepository.getRoleListWithoutToken(roleQuery);
    }

    @Override
    public List<RoleAssignment> getRoleAssignmentList(RoleAssignmentListQueryCommand roleAssignmentListQueryCommand) {
        RoleAssignmentQuery roleAssignmentQuery = appConverter.roleAssignmentListQueryCommandToRoleAssignmentQuery(roleAssignmentListQueryCommand);
        return roleMemberRepository.getRoleAssignmentList(roleAssignmentQuery);
    }

    @Override
    public List<RoleAssignment> getRoleAssignmentListWithoutToken(RoleAssignmentListQueryCommand roleAssignmentListQueryCommand) {
        RoleAssignmentQuery roleAssignmentQuery = appConverter.roleAssignmentListQueryCommandToRoleAssignmentQuery(roleAssignmentListQueryCommand);
        return roleMemberRepository.getRoleAssignmentListWithoutToken(roleAssignmentQuery);
    }
}
